package com.douing.ad.dsp.bidding.rtb;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.douing.ad.dsp.bidding.dto.AdRequestDto;
import com.douing.ad.dsp.bidding.dto.Admt;
import com.douing.ad.dsp.bidding.dto.AppImpressionDto;
import com.douing.ad.dsp.bidding.dto.AppRequestDto;
import com.douing.ad.dsp.bidding.dto.Instl;
import com.douing.ad.dsp.bidding.dto.MatchedCreativeDto;
import com.douing.ad.dsp.bidding.dto.VideoDto;
import com.douing.ad.dsp.bidding.tj.utils.NodeData;
import com.douing.ad.dsp.bidding.utils.RedisUtils;
import com.douing.ad.dsp.business.api.cache.CacheKeyManager;
import com.douing.ad.dsp.business.api.cache.OriginalityDetailInfo;

public final class CreativeMatch {

    public static List<MatchedCreativeDto> CreativeMatchImp(AdRequestDto request, NodeData nodeData,
            Map<String, NodeData> nodeDataMap) {
        String key = "";
        List<MatchedCreativeDto> matchedCreatives = new ArrayList<MatchedCreativeDto>();
        // Long[] categorys = request.getCategory();
        //
        // Long bidfloor = request.getImp().getBidfloor();
        // String impid = request.getImp().getImpId();
        // String mediaid = request.getMediaId();
        // String width = request.getImp().getBanner().getWidth().toString();
        // String height = request.getImp().getBanner().getHeight().toString();
        // String channelid = String.valueOf(request.getChannelId());
        // String uid = request.getUser().getUserId();
        // Common.WriteLog("requestid is " + request.getRequestId() + ";bidfloor is " + bidfloor);
        // long startt = System.currentTimeMillis();
        // long areaId = Common.GetCityId(request.getUser().getIp());
        // Common.WriteLog("ip service time cost:" + (System.currentTimeMillis() - startt) + " ms");
        // Common.WriteLog("ip service ip: ========" + request.getUser().getIp());
        // Common.WriteLog("ip service areaId: ========" + areaId);
        // // first matched accurate match
        // for (int i = 0; i < categorys.length; i++) {
        // key = CacheKeyManager.getOriginalityMapKey(channelid, "0", String.valueOf(categorys[i]),
        // String.valueOf(areaId), width, height);
        // Common.WriteLog("begin first matched accurate match , key is " + key);
        // getMatchedCreatives(key, matchedCreatives, uid, areaId, categorys[i], bidfloor, impid,
        // -1, mediaid, nodeData,nodeDataMap);
        // if (Common.OutOfTime(request.getReqStartTime(), nodeData)) {
        // Common.WriteLog("First matched ,out of time!");
        // break;
        // }
        // if (matchedCreatives.size() >= Common.configInfo.getMaxcreatives()) {
        // Common.WriteLog("bidding too many creatives!");
        // break;
        // }
        // }
        // if (matchedCreatives.size() == 0) {
        // Common.WriteLog("bidding match false!");
        // } else {
        // Common.WriteLog("bidding match success,number is " + matchedCreatives.size() + "!");
        // }
        return matchedCreatives;
    }

    private static void getMatchedCreatives(String key, List<MatchedCreativeDto> matchedCreatives, String uid,
            long areaId, long matchedcatid, AppImpressionDto imp, int osType, String mediaId,
            Map<String, NodeData> nodeDataMap) {
        Date dt = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        String week = Common.GetCurrentWeekOfDate(cal);
        String hour = Common.GetCurrentHour(cal);
        long startt = System.currentTimeMillis();
        List<String> matchedCreative = (List<String>) RedisUtils.hvals(key);
        Common.WriteLog("redis timespan is " + (System.currentTimeMillis() - startt));

        if (matchedCreative != null && !matchedCreative.isEmpty()) {
            for (int j = 0; j < matchedCreative.size(); j++) {
                OriginalityDetailInfo creativeInfo =
                        JSON.parseObject(matchedCreative.get(j), OriginalityDetailInfo.class);
                nodeDataMap.put(creativeInfo.getId() + "", new NodeData());
                if (creativeInfo == null || creativeInfo.getDurationInfo() == null) {
                    Common.WriteLog("redis data error key is " + key);
                    continue;
                }
                NodeData nodeData = nodeDataMap.get(creativeInfo.getId() + "");
                nodeData.setRequestDate(new Date());
                nodeData.setEntryNum(1);
                // TODO
                nodeData.setCreativeId(creativeInfo.getId() + "");
                // TODO
                nodeData.setStep1(1);
                // video
                boolean isVideo = false;
                VideoDto video = imp.getVideo();
                if (video == null && creativeInfo.getType() == 3) {
                    Common.WriteLog(
                            "creative is video and request is banner,creative id is " + creativeInfo.getId() + "!");
                    continue;
                }
                if (video != null && creativeInfo.getType() == 3) {
                    if (video.getMimes() != null && video.getMimes().contains(creativeInfo.getMimes())
                            && video.getMaxduration() >= creativeInfo.getDuration()
                            && video.getMinduration() <= creativeInfo.getDuration()) {
                        isVideo = true;
                    } else {
                        Common.WriteLog("Filter by video,creative id is " + creativeInfo.getId() + "!");
                        continue;
                    }
                }

                String filterHour = creativeInfo.getDurationInfo().getInterval().get(week);
                if (filterHour != null && !filterHour.equals("all") && !filterHour.contains(hour)) {
                    Common.WriteLog("Filter by hour,creative id is " + creativeInfo.getId() + "!");
                    continue;
                }
                // TODO
                nodeData.setStep2(1);
                if (!("").equals(uid)) {
                    String userKey = CacheKeyManager.getOriginalityFrequentnessKey(Common.GetCurrentDate(dt), uid,
                            String.valueOf(creativeInfo.getId()));
                    String userDispCount = RedisUtils.get(userKey);
                    if (userDispCount != null
                            && creativeInfo.getEverydayExposureCount() < Long.parseLong(userDispCount)) {
                        Common.WriteLog(
                                "Filter by Out of EverydayDisplayCount,creative id is " + creativeInfo.getId() + "!");
                        continue;
                    }
                }
                // TODO
                nodeData.setStep3(1);
                // add plan budget 90% confirm
                String plankey = CacheKeyManager.getPlanFreezePriceKey(String.valueOf(creativeInfo.getPlanId()));
                String planbalancetmp = RedisUtils.get(plankey);
                Long planbalance = 0L;
                if (planbalancetmp != null && !planbalancetmp.isEmpty()) {
                    planbalance = Long.valueOf(planbalancetmp);
                    if (planbalance < 10000000 && (creativeInfo.getPlanBudgetPrice() <= 1000000
                            || planbalance < creativeInfo.getPlanBudgetPrice() * 0.1)) {
                        Common.WriteLog("Filter by budget,creative id is " + creativeInfo.getId() + "!");
                        continue;
                    }
                } else {
                    Common.WriteLog("Filter by budget,creative id is " + creativeInfo.getId() + "!");
                    continue;
                }
                // TODO
                nodeData.setStep4(1);
                // end add plan budget 90% confirm
                MatchedCreativeDto mc = GetMatchedInfo(creativeInfo, areaId, matchedcatid, imp, uid, mediaId, isVideo);
                if (mc.getPlatId() == 1 && mc.getOsType() != -1 && mc.getOsType() != osType) {
                    Common.WriteLog("Filter by APPOS,creative id is " + creativeInfo.getId() + "!");
                    continue;
                }
                matchedCreatives.add(mc);
                Common.WriteLog("key " + key + " is matched! matched ad count is " + matchedCreatives.size());
                if (matchedCreatives.size() >= Common.configInfo.getMaxcreatives()) {
                    break;
                }
                // TODO
                nodeData.setStep5(1);
            }
        } else {
            Common.WriteLog("bidding match key is " + key + " ,memcached no result!");
            return;
        }
    }

    public static MatchedCreativeDto GetMatchedInfo(OriginalityDetailInfo originality, long areaId, long matchedcatid,
            AppImpressionDto imp, String uid, String mediaId, boolean isVideo) {
        MatchedCreativeDto matched = new MatchedCreativeDto();
        matched.setId(originality.getId());
        matched.setPlanId(originality.getPlanId());
        matched.setActivityId(originality.getActivityId());
        matched.setWidth(originality.getWidth());
        matched.setHeight(originality.getHeigth());
        matched.setAreaId(areaId);
        matched.setUrl(originality.getUrl());
        matched.setTargetUrl(originality.getTargetUrl());
        matched.setMaxPrice(originality.getCpmPrice());
        matched.setMatchedcatid(matchedcatid);
        matched.setCreateUserId(originality.getCreateUserId());
        matched.setCreativeTradeId(originality.getCreativeTradeId());
        matched.setBidfloor(imp.getBidfloor());
        matched.setImpid(imp.getId());
        matched.setCrowds(originality.getCrowds());
        matched.setUid(uid);
        matched.setOsType(originality.getOsType());
        matched.setMediaId(mediaId);
        if (isVideo) {
            matched.setAdmt(Admt.VIDEO);
        }
        return matched;
    }

    public static Map<String, List<MatchedCreativeDto>> AppCreativeMatchs(AppRequestDto request, NodeData nodeData,
            Map<String, NodeData> nodeDataMap) {
        Map<String, List<MatchedCreativeDto>> retMatcheds = new HashMap<String, List<MatchedCreativeDto>>();
        Long[] categorys = request.getApp().getCat();
        long startt = System.currentTimeMillis();
        long areaId = Common.GetCityId(request.getDevice().getIp());
        Common.WriteLog("ip service time cost:" + (System.currentTimeMillis() - startt) + " ms");
        for (int imp = 0; imp < request.getImp().length; imp++) {
            AppImpressionDto appimp = request.getImp()[imp];
            if (appimp == null) {
                continue;
            }
            if (!retMatcheds.containsKey(appimp.getId())) {
                retMatcheds.put(appimp.getId(), AppMatchImp(request, categorys, areaId, appimp, nodeData, nodeDataMap));
            }
        }
        return retMatcheds;
    }

    private static List<MatchedCreativeDto> AppMatchImp(AppRequestDto request, Long[] categorys, long areaId,
            AppImpressionDto imp, NodeData nodeData, Map<String, NodeData> nodeDataMap) {
        String key = "";
        List<MatchedCreativeDto> matchedCreatives = new ArrayList<MatchedCreativeDto>();
        int osType = -1;
        if (request.getDevice().getOs_type() != null) {
            osType = request.getDevice().getOs_type().ordinal();
        }
        String appid = request.getApp().getId();

        String width = "0";
        String height = "0";
        if (imp.getInstl() == Instl.VIDEO) {
            width = imp.getVideo().getWidth().toString();
            height = imp.getVideo().getHeight().toString();
        } else {
            width = imp.getBanner().getWidth().toString();
            height = imp.getBanner().getHeight().toString();
        }
        String channelid = String.valueOf(request.getChannelId());
        Common.WriteLog("requestid is " + request.getRequestId() + ";bidfloor is " + imp.getBidfloor());

        for (int i = 0; i < categorys.length; i++) {
            long categoryid = categorys[i];
            key = CacheKeyManager.getOriginalityMapKey(channelid, "1", String.valueOf(categoryid),
                    String.valueOf(areaId), width, height);
            Common.WriteLog("begin first matched accurate match , key is " + key);
            getMatchedCreatives(key, matchedCreatives, "", areaId, categoryid, imp, osType, appid, nodeDataMap);
            if (Common.OutOfTime(request.getReqStartTime(), nodeData)) {
                for (Map.Entry<String, NodeData> entry : nodeDataMap.entrySet()) {
                    entry.getValue().setIsTimeOut(1);
                }
                Common.WriteLog("First matched ,out of time!");
                break;
            }
            if (matchedCreatives.size() >= Common.configInfo.getMaxcreatives()) {
                Common.WriteLog("bidding too many creatives!");
                break;
            }
        }
        if (matchedCreatives.size() == 0) {
            Common.WriteLog("bidding match false!");
        } else {
            Common.WriteLog("bidding match success,number is " + matchedCreatives.size() + "!");
        }
        return matchedCreatives;
    }

}
